本文至此已介紹了Signal的建立(create)、更新 (update)、擷取 (retrieve) 和衍生 (derivation)。如果我有一些舊的程式碼可以產生Observables,我可以將它們轉換為Signal嗎? RxJS的互通性可以在 @angular/core/rxjs-interop
套件中使用toSignal
和toObservable
實現。今天我想介紹toSignal
,然後明天介紹toObservable
。
toSignal
的一些例子:
在以下範例中,我從API擷取所有貼文,應用toSignal
將Observable
轉換為Signal
,並顯示結果於 HTML範本中。好處是不必匯入async pipe來解析(resolve)範本中的Observable
。
// 建立一個Post類型來保存範本的實例。
type Post = {
id: number;
userId: number;
body: string;
title: string;
}
export class App {
http = inject(HttpClient);
posts = toSignal(
this.http.get<Post[]>('https://jsonplaceholder.typicode.com/posts'),
{ initialValue: [] as Post }
);
}
在App
組件中,我發出一個POST請求來擷取Post[]
的Observable
。然後將Observable
傳遞給 toSignal
以轉換為Post[]
的signal
。toSignal
的第二個選項將signal
初始化為空陣列,直到有新的結果到達。
@for (post of posts(); track post.id) {
<p><span>編號 (Id): </span>{{ post.id }}</p>
<p><span>標題 (Title): </span>{{ post.title }}</p>
<p><span>內容 (Body): </span>{{ post.body }}</p>
<hr />
}
@for
迭代posts
signal,顯示貼文的編號 (id)、標題 (title) 和內容 (body)。
這是一個使用BehaviorSubject
和scan
運算子追蹤目前計數器的舊程式碼。
之前:
deltaSub = new BehaviorSubhect(0);
finalValue$ = deltaSub.pipe(
scan((acc, v) => Math.min(0, Math.min(acc + v, 100)), 0)
);
Imports: [AsyncPipe],
<div>
<p>目前值 (Current Value): {{ finalValue$ | async }}</p>
<div>
<button (click)="deltaSub.next(-100)">|<<</button>
<button (click)="deltaSub.next(-10)">-10</button>
<button (click)="deltaSub.next(-5)">-5</button>
<button (click)="deltaSub.next(5)">+5</button>
<button (click)="deltaSub.next(10)">10</button>
<button (click)="deltaSub.next(100)">>>|</button>
</div>
</div>
將toSignal
應用於建立finalValue
signal並從imports
陣列和範本中移除async pipe。
之後:
deltaSub = new BehaviorSubhect(0);
#finalValue$ = this.deltaSub.pipe(
scan((acc, v) => Math.max(0, Math.min(acc + v, 100)), 0)
);
finalValue = toSignal(this.#finalValue$, { initialValue: 0 });
<div>
<p>目前值 (Current Value): {{ finalValue() }}</p>
<div>
<button (click)="deltaSub.next(-100)">|<<</button>
<button (click)="deltaSub.next(-10)">-10</button>
<button (click)="deltaSub.next(-5)">-5</button>
<button (click)="deltaSub.next(5)">+5</button>
<button (click)="deltaSub.next(10)">10</button>
<button
</div>
</div>
RxJS
和Signal
版本皆可達成相同的結果。
這結束了鐵人賽的第5天。
參考:
toSignal HTTP Request Demo: https://stackblitz.com/edit/stackblitz-starters-zdbab6?file=src%2Fmain.ts
toSignal Simple Counter: https://stackblitz.com/edit/stackblitz-starters-vr3z66?file=src%2Fmain.ts
一些型別上錯誤
{ initialValue: [] as Post } 應該是 { initialValue: [] as Post[] }
deltaSub = new BehaviorSubhect(0) => deltaSub = new BehaviorSubject(0);
thank you. Will fix